/*
 * CFBIRExecuter.cpp
 *
 *  Created on: 30.05.2013
 *      Author: Sheremetov Vitya
 */

#include "CFBIRExecuter.h"

/**
 * llvm-run
 */
class CFBIRExecuter
{
private:
	llvm::LLVMContext & context = llvm::getGlobalContext();
	llvm::Module * module;
	llvm::SMDiagnostic Err;

public:

	CFBIRExecuter()
	{
	}

	/**
	 * Parse file and initialize llvm module
	 * @param const char * filename - input filename
	 * @throws Error reading source
	 */
	void ReadIRFile(const char * filename)
	{
		this->module = llvm::ParseIRFile(filename, Err, this->context);
		if(!this->module)
		{
			Err.print("", llvm::errs());
			throw 0;
		}
	}

	/**
	 * Execute parsed IR code. You need to initialize llvm module
	 * (for example invoking readIRFile function) before
	 * @return int - 0 = success, 1 = fail
	 */
	int Execute()
	{
		if(!this->module)
		{
			Err.print("#1 (init module pls)", llvm::errs());
			return 1;
		}

		llvm::InitializeNativeTarget();

		// We can set some execution parameters via this object
		llvm::EngineBuilder builder(this->module);

		// This object will execute IR code
		llvm::ExecutionEngine * exe = builder.create();
		if(!exe)
		{
			Err.print("#2", llvm::errs());
			return 1;
		}

		llvm::StringRef * mainFuncName = new llvm::StringRef("main");

		// We try to find "main" function
		llvm::Function *fn = module->getFunction(*mainFuncName);
		if(!fn)
		{
			Err.print("#3 (cant found main function in the input file)", llvm::errs());
			return 1;
		}

		// analog of argv
		const std::vector< std::string > fargv;
		char _tmpenv0[] = "";
		const char* const _tmpenv1 = _tmpenv0;
		const char* const * fenvp = & _tmpenv1;
		int result = exe->runFunctionAsMain(fn, fargv, fenvp);

		return result;
	}
};
